#include <buola/gui.h>

#include <buola/gui/cicon.h>
#include <buola/os/cicontheme.h>
#include <buola/image/format.h>
#include <buola/gui/cconfig.h>
#include <buola/image/cgc.h>
#include <buola/image/algorithm/color.h>

namespace buola { namespace gui {

std::unordered_map<std::string,PIcon > CIcon::mIcons;
mutex CIcon::mStaticMutex;

CIcon::CIcon()
{
}

CIcon::~CIcon()
{
}

bool CIcon::Init(const std::string &pName)
{
    mName=pName;

    return gConfig.mIcons.GetTheme()->HasIcon(mName);
}

bool CIcon::Load(int pSize,EStyle pStyle)
{
    if(mPixmaps.count(std::make_pair(pSize,(int)pStyle))) return true;

    img::CPicture lPixmap;

    if(pStyle==NORMAL)
    {
        //Try to open file
        try
        {
            lPixmap=GetNewPixmap(pSize);
        }
        catch(XNotFound &pX)
        {
            return false;
        }
    }
    else
    {
        if(!Load(pSize,NORMAL))
            return false;

        img::CImage_rgba8 lImage=clone(img::view_rgba8(mPixmaps[std::make_pair(pSize,(int)NORMAL)].Image()));

        if(pStyle==SELECTED)
            tint(lImage,gConfig.mColors.Get(L"selection_back"));
        else
            tint(lImage,img::CColor(L"white"));
//
        lPixmap=std::move(lImage);
    }

    mPixmaps[std::make_pair(pSize,(int)pStyle)]=lPixmap;

    return true;
}

bool CIcon::Draw(img::CGC *pGC,const CPoint_d &pPos,int pSize,EStyle pStyle)
{
    if(!Load(pSize,pStyle))
    {
        msg_warn() << "Can't draw icon " << mName << "\n";
        return false;
    }

    const img::CPicture &lPixmap=mPixmaps[std::make_pair(pSize,(int)pStyle)];

    if(!lPixmap)
    {
        msg_warn() << "pixmap not found\n";
        return false;
    }
    
    CPoint_d lInc(pSize-lPixmap.Size().x,pSize-lPixmap.Size().y);

    pGC->DrawImage(pPos+lInc/2,mPixmaps[std::make_pair(pSize,(int)pStyle)]);

    return true;
}

img::CPicture CIcon::GetPixmap(int pSize,EStyle pStyle)
{
    if(!Load(pSize,pStyle))
    {
        throw XNotFound("can't load icon in GetImage");
    }

    return mPixmaps[std::make_pair(pSize,(int)pStyle)];
}

img::CPicture CIcon::GetNewPixmap(int pSize)
{
    int lRealSize=pSize;
    io::CURI lURI=gConfig.mIcons.GetTheme()->GetIcon(mName,lRealSize);
    img::CPicture lPixmap(lURI,img::FORMAT_ANY,CSize_i(lRealSize));

///\todo
//    if(lRealSize!=pSize)
//        lImage->Scale(CSize_i(lImage->GetSize().x*pSize/lRealSize,
//                        lImage->GetSize().y*pSize/lRealSize));

    return lPixmap;
}

PIcon CIcon::Get(const std::string &pName)
{
    if(pName.empty()) return nullptr;

    lock_guard<mutex> lLock(mStaticMutex);

    PIcon &lIcon=mIcons[pName];

    if(!lIcon)
    {
        CIcon *lNewIcon=new CIcon;

        if(!lNewIcon->Init(pName))
        {
            delete lNewIcon;
            lNewIcon=nullptr;
        }

        lIcon=lNewIcon; //if it is null, it will be hashed and never tried again

        //it will be returned with two references, including the one in the
        //hash table
    }

    return lIcon;
}

/*namespace gui*/ } /*namespace buola*/ }
